package com.apes.scm.account.account.model;

import com.apes.framework.jpa.DefaultPersistListener;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.Name;
import com.apes.framework.jpa.comment.Comment;
import com.apes.framework.jpa.generator.ApesGenerator;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.product.model.Brand;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.stock.model.Location;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;

import javax.persistence.*;
import java.util.Date;

/**
 * Created by HuJianlin on 2018-01-23.
 * 商品库存帐
 */
@Getter
@Setter
@SelectBeforeUpdate
@DynamicInsert
@DynamicUpdate
@Entity
@EntityListeners(DefaultPersistListener.class)
@Table(name = Stock.CONST_TABLE_NAME, indexes = {@Index(name = "u_acc_stock", columnList = "PRODUCT_ID,LOCATION_ID", unique = true)})
public class Stock extends Model {
    public static final String CONST_TABLE_NAME = "acc_stock";

    @Id
    @Column(name = "id")
    @ApesGenerator(code = CONST_TABLE_NAME, name = "商品库存帐")
    @Comment("内码")
    private Long id;  //内码

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "COMPANY_ID", referencedColumnName = "id", nullable = false)
    @Comment("公司编码")
    private PartyRole company;   //公司编码

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "LOCATION_ID", referencedColumnName = "id", nullable = false)
    @Comment("仓库库区")
    private Location location;  //仓库库区

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PRODUCT_ID", referencedColumnName = "id", nullable = false)
    @Comment("商品编码")
    private Product product;   //商品编码

    @Column(name = "CUSTODY_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("保管数")
    private double custodyQty = 0.0;   //保管数

    @Column(name = "USABLE_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("可用数")
    private double usableQty = 0.0;   //可用数

    @Column(name = "WAIT_TEST_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("待检数")
    private double waitTestQty = 0.0;   //待检数

    @Column(name = "FROZEN_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("冻结数量")
    private double frozenQty = 0.0;   //冻结数量

    public void addFrozenQty(double qty) {
        this.frozenQty += qty;
        if (frozenQty < 0) throw new RuntimeException("库存冻结数不能小于0，库区编码："+location.getId()+"商品编码："+product.getId());
    }

    @Column(name = "SALES_CONTROL_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("销售控制数")
    private double salesControlQty = 0.0;   //销售控制数

    @Column(name = "TRANSFER_IN_BILLING_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("转入制单数量")
    private double transferInBillingQty = 0.0;  //转入制单数量

    @Column(name = "TRANSFER_ISSUE_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("转储发货在途")
    private double transferIssueQty = 0.0;  //转储发货在途

    @Column(name = "TRANSFER_RECEIVE_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("转储收货在途")
    private double transferReceiveQty = 0.0;  //转储收货在途

    @Column(name = "PURCHASE_BILLING_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("订货制单数量")
    private double purchaseBillingQty = 0.0;  //订货制单数量

    @Column(name = "PURCHASING_WAY_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("订货在途")
    private double purchasingWayQty = 0.0;   //订货在途

    @Column(name = "LEND_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("领用在途")
    private double lendQty = 0.0;   //领用在途

    @Column(name = "REQUIRE_BILLING_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("要货制单数量")
    private double requireBillingQty = 0.0;   //要货制单数量


    public void addRequireBillingQty(double qty){
        this.requireBillingQty += qty;
        if (this.requireBillingQty < 0) this.requireBillingQty = 0; // 限制要货数量不允许小于零，存在要少采多的情况
    }

    @Column(name = "LAST_IN_DATE")
    @Comment("最后入库日期")
    private Date lastInDate;  //最后入库日期

    @Column(name = "LAST_OUT_DATE")
    @Comment("最后出库日期")
    private Date lastOutDate;   //最后出库日期

    @Column(name = "THE_MAX_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("最高限量")
    private double theMaxQty = 0.0;  //最高限量

    @Column(name = "THE_MIN_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("最低限量")
    private double theMinQty = 0.0;  //最低限量

    @Column(name = "SAFETY_STOCK_QTY", nullable = false, columnDefinition = "NUMBER(16,4) DEFAULT 0")
    @Comment("安全库存")
    private double safetyStockQty = 0.0;   //安全库存

    @Column(name = "oos", nullable = false, columnDefinition = "number(1,0) default 0")
    @Comment("无库存销售标记")
    private boolean oos = false; //无库存销售标记（OOS：out of stock）


    // 品牌
    @Transient
    private Brand brand;
    /*
     * 功能：更新保管数
     */
    public void addCustodyQty(double qty) {
        this.custodyQty += qty;
        if(qty > 0) {
            lastInDate = new Date();
        }else if(qty < 0) {
            lastOutDate = new Date();
        }
        if (custodyQty < 0) throw new RuntimeException("商品：" + this.getProduct().getId() + "保管数不允许小于零！");
    }

    /*
     * 功能：更新可用数
     */
    public void addUsableQty(double qty) {
        this.usableQty += qty;
        if(this.usableQty < 0 && qty < 0) {
            throw new RuntimeException("商品：" + this.getProduct().getId() + "可用数不允许小于零！");
        }
    }

    /*
     * 功能：更新可用数(支持超卖)
     */
    public void addOverUsableQty(double qty) {
        this.usableQty += qty;
    }

    @Name
    @Transient
    private double marketableQty; //可销售数量 = 可用数量+待检测数量+可卖控制数量-冻结数量
    public double getMarketableQty() {
        return this.getUsableQty()+this.getWaitTestQty()+this.getSalesControlQty()-this.getFrozenQty();
    }

    @Transient
    private double marketableQtyFa;
    public double getMarketableQtyFa() { //方案可销售库存
        return this.getUsableQty()+this.getWaitTestQty()+this.getSalesControlQty() + this.requireBillingQty -this.getFrozenQty();
    }


    @Transient
    private double marketableQtyFaDs;
    public double getMarketableQtyFaDs() { //(可用数 - 冻结数) + (转储收货在途 + 订货在途 + 转入制单数 + 要货数) + 销售控制数
        return this.getUsableQty() + this.getTransferReceiveQty() + this.getPurchasingWayQty() + this.getTransferInBillingQty()
                + this.getRequireBillingQty() +  this.getSalesControlQty() -this.getFrozenQty() ;
    }
    @Transient
    public Brand getBrand(){
        if (product == null || product.getBrand() == null) return null;
        return product.getBrand();
    }

    public void setCompany(PartyRole company) {
        if (location != null && !location.getCompany().equals(company)) {
            throw new RuntimeException("仓库库区公司与帐目公司不一致！");
        }
        this.company = company;
    }

    public void setLocation(Location location) {
        if (company != null && !location.getCompany().equals(company)) {
            throw new RuntimeException("仓库库区公司与帐目公司不一致！");
        }
        this.location = location;
    }
}
